package com.ruoyi.aitu8cloud.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.ruoyi.aitcommon.anotation.ServiceLog;
import com.ruoyi.aitcommon.service.IAitEntityInfoService;
import com.ruoyi.aitcommon.utils.AITException;
import com.ruoyi.aitcommon.utils.EntityCache;
import com.ruoyi.aitcommon.utils.ExceptionUtils;
import com.ruoyi.aitcommon.utils.JSONResult;
import com.ruoyi.aitcommon.utils.ListMapUtils;
import com.ruoyi.aitcommon.utils.LogUtils;
import com.ruoyi.aitcommon.utils.MapUtils;
import com.ruoyi.aitcommon.utils.RestServiceUtils;
import com.ruoyi.aitcommon.vo.AggMap;
import com.ruoyi.common.constant.HttpStatus;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;

/**
 * U8Cloud接口的封装类 使用最新的U8CloudOPENAPI接口
 * 接口文档地址:https://apidoc.yyu8c.com/#/
 * @author Administrator 
 */
@Service
public class U8CloudRestService {
	@Autowired
	IAitEntityInfoService infoService;
	@Autowired
	EntityCache entityCache;

	private List<AggMap> filterlist;

	/**
	 * 通用u8cloud接口调用方法
	 * 所有服务均通过该方法调用u8cloud OPENAPI
	 * <pre>
	 * 实现功能:
	 * 1. 组装OPENAPI JSON
	 * 2. 判断返回是否正确
	 * 3. 处理返回为通用JSON对象
	 * </pre>
	 * @param context
	 * @param url
	 * @param data
	 * @return
	 * @throws Exception
	 */
	private JSONObject restInvoke(Map<String, Object> context, String url, Map<String, Object> data)
			throws Exception {
		if (data == null) {
			return JSONResult.success("没有数据");
		}

//		构造U8Cloud参数
		ExceptionUtils.checkBlankOrUndefined(context, "context为空!");
		ExceptionUtils.checkBlankOrUndefined(context.get("system"), "context.system为空!");
		ExceptionUtils.checkBlankOrUndefined(context.get("usercode"), "context.usercode为空!");
		ExceptionUtils.checkBlankOrUndefined(context.get("password"), "context.password为空!");
//		处理head
		Map<String, Object> head = new HashMap<String, Object>();
		head.put("system", context.get("system"));
		head.put("usercode", context.get("usercode"));
//		密码使用hutool的md5加密算法,返回16进制字符串
		String md5Hex = DigestUtil.md5Hex(context.get("password").toString());
		head.put("password", md5Hex);

//		调用U8Cloud OPENAPI
		JSONObject retjson = RestServiceUtils.post(url, head,new JSONObject(data));

//		处理U8Cloud服务返回
		if (!retjson.containsKey("status"))
			throw new Exception("返回数据错误,无[status]!");
		if (!retjson.getString("status").equals("success")) {
			String msg = retjson.getString("errormsg");
			throw new Exception("U8Cloud调用报错:" + msg);
		}
		return retjson;
	}

	/**
	 * 查询接口封装
	 * @param context	上下文{entityName,system,usercode,password....}
	 * @param url		调用地址
	 * @param query		查询条件JSON
	 * @return			查询结果数据
	 * @throws Exception
	 */
	@ServiceLog("U8Cloud查询服务")
	public List<Map<String, Object>> query(Map<String, Object> context, String url, Map<String, Object> query
			,Map<String,Object> transMap) throws Exception {
//		调用接口获取JSON
		JSONObject json=this.restInvoke(context,url,query);
//		处理返回值
		JSONArray datalist= json.getJSONObject("data").getJSONArray("datas");
		List<Map<String, Object>> retlist = this.AggVO2ListMap(datalist, transMap);
		return retlist;
	}
	
	/**
	 * 将u8cloud返回的aggvo转换为listmap
	 * @param datas aggvo集合
	 * @param map 转换映射
	 * <pre>
	 * 举例:
	 * "transMap":{
			//头部字段
			"doc":["vpraycode","operator_code","pk_corp"],
			//行字段
			"line":["crowno","inv_code","npraynum"],
			//key组合字段
			"key":{
				"field":"pkey",
				"text":["vpraycode","crowno"]
			}
		}
	 * </pre>
	 * @return listmap
	 * @throws Exception 
	 */
	private List<Map<String,Object>> AggVO2ListMap(JSONArray datas,Map<String,Object> transMap) throws Exception{
		if(datas==null||datas.size()==0)
			return null;
		ExceptionUtils.checkBlankOrUndefined(transMap, "transMap为空");
		ExceptionUtils.checkBlankOrUndefined(transMap.get("key"), "transMap.key为空");
		
		List<Map<String,Object>> retlist=new ArrayList<Map<String,Object>>();
		
		for(Object obj : datas) {
			JSONObject agg=(JSONObject)obj;
			JSONObject doc=agg.getJSONObject("parentvo");
			JSONArray lines=agg.getJSONArray("childrenvo");
			
			JSONArray docfields=null;
			JSONArray linefields=null;
			
			if(transMap.get("doc")!=null) {
				docfields=(JSONArray)transMap.get("doc");
			}
			if(transMap.get("line")!=null) {
				linefields=(JSONArray)transMap.get("line");
			}
			
			if(linefields!=null) {
//				如果需要取行字段,循环每行处理
				for(Object lineobj : lines) {
					JSONObject line=(JSONObject)lineobj;
					Map<String,Object> retitem=new LinkedHashMap<String,Object>();
					if(docfields!=null) {
//						取头数据
						for(Object field:docfields) {
							retitem.put(field.toString(), doc.get(field.toString()));
						}
					}
					for(Object field:linefields) {
//						取行数据
						retitem.put(field.toString(), line.get(field.toString()));
					}
					retlist.add(retitem);
				}
			}else if(docfields!=null){
//				只取头数据
				Map<String,Object> retitem=new LinkedHashMap<String,Object>();
				for(Object field:docfields) {
					retitem.put(field.toString(), doc.get(field.toString()));
				}
				retlist.add(retitem);
			}
			
//			处理返回集合的主键
			String keyfield=MapUtils.getPathString("key.field", transMap);
			JSONArray textfields=(JSONArray)MapUtils.getPathObject("key.text", transMap);
			for(Map<String,Object> item : retlist) {
				List<String> keys=new ArrayList<String>();
				for(Object field:textfields) {
					keys.add(item.get(field).toString());
				}
				String text = StrUtil.join("-", keys);
				item.put(keyfield, text);
			}
		}
		return retlist;
	}
	
	/**
	 * 档案/单据保存接口封装
	 * <pre>
	 * 实现如下内容:
	 *   数据预处理
	 *   循环单条调用接口
	 *   循环中处理每条数据异常
	 *   entityInfo插入数据库
	 * </pre>
	 * @param context    上下文{entityName,system,usercode,password....}
	 * @param url        调用地址
	 * @param datas      数据列表(非AGG)
	 * @param entityInfo
	 * @return
	 * @throws Exception
	 */
	@ServiceLog("U8Cloud单据保存服务")
	public List<JSONObject> docSave(Map<String, Object> context, String url, List<Map<String, Object>> datas,
			JSONObject entityInfo) throws Exception {
		List<JSONObject> retlist = new ArrayList<JSONObject>();

//		校验参数
		ExceptionUtils.checkBlankOrUndefined(context, "context为空");
		ExceptionUtils.checkBlankOrUndefined(url, "url为空");
		ExceptionUtils.checkBlankOrUndefined(entityInfo, "entityInfo为空");
		
//		预处理:VO转换,缓存过滤,token等处理
		PreDeal(context, datas, entityInfo);

		for (AggMap data : filterlist) {
//			循环单条处理
			try {
//				构造接口aggvo
				Map<String,Object> doc=new LinkedHashMap<String,Object>();
				doc.put(context.get("entityName").toString(), data.toMap("parentvo", "childrenvo"));
//				调用 U8 接口
				JSONObject retjson = restInvoke(context, url, doc);
//				处理实体日志和缓存
				infoService.insertAitEntityInfo(entityInfo, data, null);
//				处理返回
				retlist.add(retjson);
			} catch (Exception ex) {
//				处理实体日志和缓存-失败信息
				infoService.insertAitEntityInfo(entityInfo, data, ex);
//				处理返回
				retlist.add(JSONResult.error(ex.getMessage()));
			}
		}
		return retlist;
	}

	/**
	 * 预处理方法
	 * <pre>
	 * 包含但不限于下述内容:
	 *   AggVO转换
	 *   重复数据过滤
	 *   token获取
	 *   等等
	 * </pre>
	 * @param context
	 * @param datas
	 * @param entityInfo
	 * @throws Exception
	 */
	private void PreDeal(Map<String, Object> context, List<Map<String, Object>> datas, JSONObject entityInfo)
			throws Exception {
		// context校验
		ExceptionUtils.checkBlankOrUndefined(context.get("entityName"), "context.entityName为空");
		ExceptionUtils.checkBlankOrUndefined(context.get("headkey"), "context.headkey为空");
		ExceptionUtils.checkBlankOrUndefined(context.get("fenge"), "context.fenge为空");
		
		// 构造AggVO
		List<AggMap> aggvos = ListMapUtils.transAggVO(datas, context.get("headkey").toString(), context.get("fenge").toString());
		// 从缓存过滤重复数据
		this.filterlist=entityCache.filterAggChange(entityInfo, aggvos);
		
	}
}
